<?php

namespace yifang\db;

use Exception;

class Query extends BaseQuery
{
    use concern\JoinQuery;
    use concern\ParamsBind;
    use concern\TableFieldInfo;

    /**
     * 获取当前数据表的主键
     * @access public
     * @return string|array
     */
    public function getPk()
    {
        if (empty($this->pk)) {
            $this->pk = $this->connection->getPk($this->getTable());
        }
        return $this->pk;
    }

    /**
     * 创建子查询SQL
     * @access public
     * @param bool $sub 是否添加括号
     * @return string
     * @throws Exception
     */
    public function buildSql($sub = true)
    {
        return $sub ? '( ' . $this->fetchSql()->select() . ' )' : $this->fetchSql()->select();
    }

    /**
     * 获取执行的SQL语句而不进行实际的查询
     * @access public
     * @param bool $fetch 是否返回sql
     */
    public function fetchSql($fetch = true)
    {
        $this->options['fetch_sql'] = $fetch;
        if ($fetch) {
            return new Fetch($this);
        }
        return $this;
    }

    /**
     * 指定group查询
     * @access public
     * @param string|array $group GROUP
     * @return $this
     */
    public function group($group)
    {
        $this->options['group'] = $group;
        return $this;
    }

    /**
     * 指定having查询
     * @access public
     * @param string $having having
     * @return $this
     */
    public function having($having)
    {
        $this->options['having'] = $having;
        return $this;
    }

    /**
     * 指定distinct查询
     * @access public
     * @param bool $distinct 是否唯一
     * @return $this
     */
    public function distinct($distinct = true)
    {
        $this->options['distinct'] = $distinct;
        return $this;
    }

    /**
     * 指定强制索引
     * @access public
     * @param string $force 索引名称
     * @return $this
     */
    public function force($force)
    {
        $this->options['force'] = $force;
        return $this;
    }

    /**
     * 查询注释
     * @access public
     * @param string $comment 注释
     * @return $this
     */
    public function comment($comment)
    {
        $this->options['comment'] = $comment;
        return $this;
    }

    /**
     * 获取当前数据表的自增主键
     * @access public
     * @return string|null
     */
    public function getAutoInc()
    {
        $tableName = $this->getTable();
        if (empty($this->autoinc) && $tableName) {
            $this->autoinc = $this->connection->getAutoInc($tableName);
        }
        return $this->autoinc;
    }


    /**
     * 字段值增长
     * @access public
     * @param string  $field    字段名
     * @param float   $step     增长值
     * @return $this
     */
    public function inc($field, $step = 1)
    {
        $this->options['data'][$field] = ['INC', $step];
        return $this;
    }

    /**
     * 字段值减少
     * @access public
     * @param string  $field    字段名
     * @param float   $step     增长值
     * @return $this
     */
    public function dec($field, $step = 1)
    {
        $this->options['data'][$field] = ['DEC', $step];
        return $this;
    }

    /**
     * 分批数据返回处理
     * @access public
     * @param integer      $count    每次处理的数据数量
     * @param callable     $callback 处理回调方法
     * @param string|array $column   分批处理的字段名
     * @param string       $order    字段排序
     * @return bool
     * @throws Exception
     */
    public function chunk($count, callable $callback, $column = null, $order = 'asc')
    {
        $options = $this->getOptions();
        $column  = $column ?: $this->getPk();
        $pk=$this->getPk();
        if (isset($options['order'])) {
            unset($options['order']);
        }
        $bind = $this->bind;
        if (is_array($column)) {
            $times = 1;
            $query = $this->options($options)->page($times, $count);
        } else {
            $query = $this->options($options)->limit($count);
            if (strpos($column, '.')) {
                list($alias, $key) = explode('.', $column);
            } else {
                $key = $column;
            }
        }
        $resultSet = $query->order($column, $order)->select();
        while (count($resultSet) > 0) {
            if (false === call_user_func($callback, $resultSet)) {
                return false;
            }
            if (isset($times)) {
                $times++;
                $query = $this->options($options)->page($times, $count);
            } else {
                $end    = end($resultSet);
                $lastId = $end[$pk];
                $query = $this->options($options)->limit($count)->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId);
            }
            $resultSet = $query->bind($bind)->order($column, $order)->select();
        }
        return true;
    }

    /**
     * 使用表达式设置数据
     * @access public
     * @param string $field 字段名
     * @param string $value 字段值
     * @return $this
     */
    public function exp($field, $value)
    {
        $this->options['data'][$field] = new Raw($value);
        return $this;
    }

    /**
     * 设置是否REPLACE
     * @access public
     * @param bool $replace 是否使用REPLACE写入数据
     * @return $this
     */
    public function replace($replace = true)
    {
        $this->options['replace'] = $replace;
        return $this;
    }
}